/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2012-2020.
 * Description: Linux GMAC debugging Ethernet port driver
 * Author: yanbo
 * Create: 2012-12-25
 */
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <asm/cacheflush.h>
#include <linux/phy.h>
#include <linux/of_mdio.h>
#include <linux/platform_device.h>
#include <linux/kthread.h>

#include "ge_reg.h"
#include "ppe_reg.h"
#include "gmac.h"

#define OFFSET_0	0
#define OFFSET_1	1
#define OFFSET_2	2
#define OFFSET_3	3
#define OFFSET_4	4
#define OFFSET_5	5

/* Log control macro definition */
unsigned int print_err;


static struct task_struct *mytask;

#define V_ERROR   0
#define V_INFO    1
#define V_DEBUG   2
#ifdef V_DEBUG
#define vtrace(level, fmt, args...) do { \
	if (print_err >= level) { \
		printk("%d %s: ", __LINE__, __func__); \
		printk(fmt, ##args); \
	} \
} while (0)
#else
#define vtrace(level, fmt, args...)
#endif  /* MAC_DEBUG */

#define GPIO_PORT_3	3
/* GPIO112 optical module is not inserted to high level. Otherwise, the low level */
#define GPIO_PIN_112	(1 << (112 % 32))

int gmac_not_exist;

/* The global variable */
volatile int thread_end;

/* Macro Definition */
#define  BOARD_FPGA			1 /* Hi1381 fpga board */
#define  BOARD_UBBPD		2 /* Ubbp D board */
#define  BOARD_UBBPV2		3 /* Ubbp V2 board */
#define  BOARD_USER_DEF		4 /* self-defined type */

#define GMAC_BASE_ADDR		0xf2800000 /* 1381 GMAC channel0 address */
#define GMAC_BASE_IRQNUM	197 /* 1381 GMAC channel0 irq num */
#define GMAC_PHY_PORT_NUM      3       /* The GMAC physical port number */

#define GMAC_DEV_ADDR0         0X00    /* 1381 GMAC device address 0 */
#define GMAC_DEV_ADDR1          0X0a   /* 1381 GMAC device address 1 */
#define GMAC_DEV_ADDR2          0X0b   /* 1381 GMAC device address 2 */
#define GMAC_DEV_ADDR3          0X0c   /* 1381 GMAC device address 3 */
#define GMAC_DEV_ADDR4          0X0d   /* 1381 GMAC device address 4 */
#define GMAC_DEV_ADDR5          0X0e   /* 1381 GMAC device address 5 */

#define SHIFT_6_BITS            6
#define SHIFT_8_BITS           8       /* device address shift 8 bits */
#define SHIFT_16_BITS          16      /* device address shift 16 bits */
#define SHIFT_24_BITS          24      /* device address shift 24 bits */

#define DELAY_10               10
#define SLEEP_500              500

#define NO_SMMU			3 /* Align mmu */
#define LENGTH_OF_DOUBLE_BYTE	16 /* Line break every double bytes */
#define MAX_OF_DOUBLE_BYTE	15 /* Line break every double bytes */

int     param_board = BOARD_UBBPD;
int     param_smmu = NO_SMMU;
module_param(param_board, int, (S_IRUSR|S_IRGRP));
module_param(param_smmu, int, (S_IRUSR|S_IRGRP));

#define MAX_CHANNEL_NUM		8 /* 1381 maximum GE channel number */
#define MAX_POOL_NUM		31 /* 1381 maximum pool channel number */
#define MAX_GROUP_NUM		31 /* 1381 Maximum group channel number */
#define MAX_FIFO_NUM		2048 /* 1381 fifo of the maximum depth */
#define MAX_MDIO_NUM		1 /* 1381 maximum ID of the MDIO */
#define MAX_PHY_NUM			0x1f /* 1381 maximum phy IDs */

#define CHANNEL_SPECIAL		8 /* 1381 GE8 is special channels and only supports the MII */

unsigned int param_channel = 3;
unsigned int param_pool = 31;
unsigned int param_group = 18;
unsigned int param_fifo_start = 1500;
unsigned int param_fifo_size = 255;
unsigned int param_mdio_num;
unsigned int param_phy_num;
unsigned int param_phy_start = 1;
module_param(param_channel, uint, (S_IRUSR|S_IRGRP));
module_param(param_pool, uint, (S_IRUSR|S_IRGRP));
module_param(param_group, uint, (S_IRUSR|S_IRGRP));
module_param(param_fifo_start, uint, (S_IRUSR|S_IRGRP));
module_param(param_fifo_size, uint, (S_IRUSR|S_IRGRP));
module_param(param_mdio_num, uint, (S_IRUSR|S_IRGRP));
module_param(param_phy_num, uint, (S_IRUSR|S_IRGRP));
module_param(param_phy_start, uint, (S_IRUSR|S_IRGRP));

#define PPE_COMMON_POOL_NUM (param_pool) /* Current PPE_COMMON buffer FIFO number */

/* PPE_CFG_RX_CFF_ADD is 32 buffer FIFO FIFO passive allocation BUF address corresponding to */
#define PPE_CFG_RX_CFF_ADDR_REG                     (0x0100 + PPE_COMMON_POOL_NUM * 0x4)
/* PPE_CFG_RX_BUFF_FIFO_THRSLD is buffer FIFO threshold register */
#define PPE_CFG_RX_BUFF_FIFO_THRSLD_REG             (0x0200 + PPE_COMMON_POOL_NUM * 0x4)
/* PPE_CFG_POOL_GRP is 32 buffer FIFO can be allocated to the GRP */
#define PPE_CFG_POOL_GRP_REG                        (0x0300 + PPE_COMMON_POOL_NUM * 0x4)
/* PPE_CFG_RX_BUFF_FIFO_RX_BUF_SIZE is buffer FIFO buffer size configuration register */
#define PPE_CFG_RX_BUFF_FIFO_RX_BUF_SIZE_REG        (0x0400 + PPE_COMMON_POOL_NUM * 0x4)
/* PPE_CFG_RX_BUFF_FIFO_SIZE is buffer FIFO size configuration register */
#define PPE_CFG_RX_BUFF_FIFO_SIZE_REG               (0x0500 + PPE_COMMON_POOL_NUM * 0x4)
/* PPE_CURR_BUF_CNT is number of cached pool_0~pool_31 buffer pointer */
#define PPE_CURR_BUF_CNT_REG                        (0xA200 + PPE_COMMON_POOL_NUM * 0x4)

#define HI1381_TX_BD_RING_SIZE      8

#define HI1381_RX_BD_RING_ADDR      (param_fifo_start)
#define HI1381_RX_BD_RING_SIZE      (param_fifo_size)

#define RX_RING_SIZE                HI1381_RX_BD_RING_SIZE
#define TX_RING_SIZE                HI1381_TX_BD_RING_SIZE


#define GMAC_MDIOBUS_NAME   "hisi_mdio"

/* The unit is CACHE LINE SIZE */
#define GMAC_RX_SKIP1            0x00
#define GMAC_RX_SKIP2            0x00    /* This design SKIP2 must be greater than or equal to 1 */
#define GMAC_RX_DESCR            0x01    /* hardware parsing information occupies. It has a fixed value of 1 */
#define GMAC_RX_ALIGN            2

#define CACHE_LINE_SIZE          64
#define PACKET_HEAD_SIZE         ((GMAC_RX_SKIP1 + GMAC_RX_SKIP2 + GMAC_RX_DESCR) * CACHE_LINE_SIZE)
#define PACKET_DATA_SIZE         0x600     /* >MTU 1518, cache line align */
#define RX_BUFFER_SIZE           (PACKET_HEAD_SIZE + PACKET_DATA_SIZE)
#define RX_BUFFER_NUM            4


#define GMAC_PPE_RX_PKT_MAX_LEN  379

#define GMAC_MAX_PKT_LEN         1516
#define GMAC_SHORT_PKT_LEN	 31
/* Provided for the packet descriptors */
#define GMAC_DESC_LEN            (16 * 4)
#define GMAC_DESC_L2_ERR_ERROR   1
#define GMAC_DESC_L2_ERR_MASK    0x01

/* Transmitter timeout */
#define TX_TIMEOUT (2 * HZ)

#define GMAC_TX_IDLE             0x77777777
#define GMAC_TX_START            0x5a5a5a5a
#define GMAC_TX_END              0x00000000

#define GMAC_TX_MAX_PKT		 100
#define GMAC_RX_MIN_PKT_LEN      20

#define ENABLE      0x1
#define DISABLE     0x0
#define SGMII_NOEND     0x200000 /* SGMII self-negotiation not completed */
#define PHY_LINKED     0x8000 /* phy links at the bottom layer. */

#define RECV_MAXPKTS_ONETIME 500

enum gmac_direction {
	GMAC_TX,
	GMAC_RX,
	GMAC_RX_DESCRIPTION
};

/* Tx structure */
struct tx_buf {
	void           *next;
	unsigned int   *tx_state;
	struct sk_buff *tx_skb;
	struct tx_descript  *tx_desc;
};

/* Tx Buffer Ring */
struct tx_buf_ring {
	struct tx_buf  *tx_cur;
	struct tx_buf  *tx_free;
	struct tx_buf   buf_ring[TX_RING_SIZE];
};

struct gmac_private {
	struct sk_buff          *rx_skbuff[MAX_FIFO_NUM];
	unsigned int            rx_skb_cur;
	unsigned int            rx_skb_mask;

	struct tx_buf_ring      tx_ring;     /* Tx Buffer Ring               */

	unsigned long		sys_ctrl_base_addr;

	unsigned long		ppe_base_addr;

/* The initialization of packet descriptors and sends a clear address has a memory
 * because it later address to ensure cacheline alignment may be mobile,
 * Therefore, you need to save the allocation is released when original address to uninstall
 */
	void                    *ppe_tx_desc;
	void                    *ppe_tx_status;

	spinlock_t spinlock;
	struct net_device_stats statistics;
	unsigned int msg_enable;

	char *phy_name;
	struct phy_device *phy;

	int duplex_old;
	int speed_old;
	int link_old;

	unsigned int ev_napi_rx;     /* mask of NAPI rx events */
	unsigned int ev_rx;      /* rx event mask          */
	unsigned int ev_tx;      /* tx event mask          */

	struct tasklet_struct rx_tasklet;
};

#define RESET_ENABLE	0xffffffff

#ifdef PRINT_PKT
static void gmac_print_pkt(char *packet, int length, enum gmac_direction dir)
{
	unsigned int i;

	if ((length <= 0) || (packet == NULL)) {
		pr_err("the pkt is error\n");
		return;
	}

	switch (dir) {
	case GMAC_TX:
		pr_err("GMAC Tx Pkt, Addr=%pK, Len=%d\n", packet, length);
		break;

	case GMAC_RX:
		pr_err("GMAC Rx Pkt, Addr=%pK, Len=%d\n", packet, length);
		break;

	case GMAC_RX_DESCRIPTION:
		pr_err("GMAC Rx Pkt Description, Addr=%pK, Len=%d\n", packet, length);
		break;
	}

	for (i = 0; i < length; i++) {
		pr_err("%02x ", packet[i]);
		if (i % LENGTH_OF_DOUBLE_BYTE == MAX_OF_DOUBLE_BYTE)
			pr_err("\n");
	}
	pr_err("\n");
}
#endif

#define  gmac_write_and_check_err_return(value, addr)  do {  \
	unsigned int cmp;  \
	gmac_writel(value, addr);  \
	cmp = gmac_readl(addr);  \
	if (cmp != (value)) {  \
		pr_err("%s failed: actual read value:0x%X != expected write value:0x%X \n", __func__, cmp, value);  \
		return GMAC_ERROR;  \
	}  \
} while (0)

static int gmac_set_channel(unsigned long base_addr, unsigned int dir, unsigned int en)
{
	port_en_u port;

	port.u32 = gmac_readl(base_addr + GE_PORT_EN_REG);
	/* if dir is 0, dir is rx, other is tx */
	if (dir)
		port.bits.tx_en = en ? 1 : 0;
	else
		port.bits.rx_en = en ? 1 : 0;
	gmac_write_and_check_err_return(port.u32, base_addr + GE_PORT_EN_REG);

	return GMAC_OK;
}

/*****************************************************************************
  Function description: Disable MAC chip obtained from the BMU memory function
 *****************************************************************************/
static int gmac_close_bmu(struct net_device *dev)
{
	union rx_buffer_size rx_size;

	struct gmac_private *gmac_priv = netdev_priv(dev);
	unsigned long ppe_addr = gmac_priv->ppe_base_addr;
	rx_size.u32 = gmac_readl(ppe_addr + PPE_CFG_RX_BUFF_FIFO_RX_BUF_SIZE_REG);
	rx_size.bits.cf_rx_cfg_req_en = 0;    /* not enable: BMU receive buffer address enable */
	gmac_write_and_check_err_return(rx_size.u32, (ppe_addr + PPE_CFG_RX_BUFF_FIFO_RX_BUF_SIZE_REG));

	return GMAC_OK;
}

/*****************************************************************************
  Function description: Disable MAC chip and POE-related functions
 *****************************************************************************/
static int gmac_close_poe(struct net_device *dev)
{
	union bus_ctrl ppe_bus;
	unsigned long base_addr;

	base_addr = dev->base_addr;
	ppe_bus.u32 = gmac_readl(base_addr + PPE_CFG_BUS_CTRL_REG);
	ppe_bus.bits.cf_we_enable = 0;   /* not enable:  working descriptor write enable */
	gmac_write_and_check_err_return(ppe_bus.u32, (base_addr + PPE_CFG_BUS_CTRL_REG));

	return GMAC_OK;
}

static int gmac_port_mode_set(unsigned long base_addr, unsigned int speed)
{
	union port_mode port;
	union mode_change_en change;
	/* Check whether the parameter is valid. */
	/* Set the port mode */
	port.u32 = gmac_readl(base_addr + GE_PORT_MODE_REG);
	port.bits.port_mode = speed;
	gmac_write_and_check_err_return(port.u32, base_addr + GE_PORT_MODE_REG);

	change.u32 = gmac_readl(base_addr + GE_MODE_CHANGE_EN_REG);
	change.bits.mode_change_en = 1;
	gmac_write_and_check_err_return(change.u32, base_addr + GE_MODE_CHANGE_EN_REG);

	return GMAC_OK;
}

static void gmac_grp_vmid_set(unsigned long base_addr)
{
	union cfg_qos_grp_vmid_gen qos;

	qos.u32 = gmac_readl(base_addr + PPE_CFG_QOS_GRP_VMID_GEN_REG);
	/* Configure grp and VMID generation mode */
	/* grp and VMID parsing mode: 0. grp and VMID fixed value: 1 */
	qos.bits.vmid_mode = 1;
	qos.bits.grp_mode = 1;

	qos.bits.def_grp = param_group;
	gmac_writel(qos.u32, base_addr + PPE_CFG_QOS_GRP_VMID_GEN_REG);
}

static inline void gmac_pool_grp_set(unsigned long ppe_base_addr)
{
	/* The buffer pool can be used for all GRP */
	gmac_writel(1 << param_group, (ppe_base_addr + PPE_CFG_POOL_GRP_REG));
}

static void gmac_mac_address_set(struct net_device *dev, unsigned long base_addr)
{
	unsigned int mac_addr_l;
	unsigned int mac_addr_h;

	/* Setting the MAC address */
	dev->dev_addr[OFFSET_0] = GMAC_DEV_ADDR0;
	dev->dev_addr[OFFSET_1] = GMAC_DEV_ADDR1;
	dev->dev_addr[OFFSET_2] = GMAC_DEV_ADDR2;
	dev->dev_addr[OFFSET_3] = GMAC_DEV_ADDR3;
	dev->dev_addr[OFFSET_4] = GMAC_DEV_ADDR4;
	dev->dev_addr[OFFSET_5] = GMAC_DEV_ADDR5;

	mac_addr_h  = (dev->dev_addr[OFFSET_0] << SHIFT_8_BITS) | (dev->dev_addr[OFFSET_1]);
	mac_addr_l = (dev->dev_addr[OFFSET_2] << SHIFT_24_BITS)
		| (dev->dev_addr[OFFSET_3] << SHIFT_16_BITS)
		| (dev->dev_addr[OFFSET_4] << SHIFT_8_BITS)
		| (dev->dev_addr[OFFSET_5]);

	gmac_writel(mac_addr_l, base_addr + GE_STATION_ADDR_LOW_2_REG);
	gmac_writel(mac_addr_h, base_addr + GE_STATION_ADDR_HIGH_2_REG);
}

static int gmac_duplex_type_set(unsigned long base_addr, unsigned int duplex_type)
{
	union duplex_type reg_value;

	reg_value.u32 = 0;
	reg_value.bits.duplex_sel = duplex_type ? 1 : 0;
	gmac_write_and_check_err_return(reg_value.u32, base_addr + GE_DUPLEX_TYPE_REG);

	return GMAC_OK;
}

static int gmac_pkt_store_format_set(unsigned long base_addr, const ppe_pkt_store_ctrl_cfg_s *rx_ctrl)
{
	union rx_ctrl ppe;

	ppe.u32 = gmac_readl(base_addr + PPE_CFG_RX_CTRL_REG);
	/* Set the RX control information */
	/* Receive message parsing enable */
	ppe.bits.cf_rx_align_num = rx_ctrl->cf_rx_align_num;
	/* The GMAC physical port number */
	ppe.bits.cf_node_code     = GMAC_PHY_PORT_NUM;
	gmac_write_and_check_err_return(ppe.u32, base_addr + PPE_CFG_RX_CTRL_REG);

	return GMAC_OK;
}

/*****************************************************************************
  Function description: input mode and parsing packets can be set and queried.
 *****************************************************************************/
static int gmac_pkt_input_parse_mode_set(unsigned long base_addr, const ppe_pkt_parse_mode_cfg_s *mode)
{
	union rx_pkt_mode pkt_mode;
	/* Set the packet input mode */
	pkt_mode.u32 = gmac_readl(base_addr + PPE_CFG_RX_PKT_MODE_REG);
	pkt_mode.bits.cf_l2_skip1    = mode->cf_skip1_len;
	pkt_mode.bits.cf_l2_skip2    = mode->cf_skip2_len;
	pkt_mode.bits.cf_parse_mode  = mode->cf_parse_mode;
	gmac_write_and_check_err_return(pkt_mode.u32, base_addr + PPE_CFG_RX_PKT_MODE_REG);

	return GMAC_OK;
}

static int gmac_bus_ctrl_set(unsigned long base_addr, unsigned int value)
{
	union bus_ctrl bus;

	/* If the system is set to Big endian, the control word is big endian, data is in big endian */
	bus.u32 = gmac_readl(base_addr + PPE_CFG_BUS_CTRL_REG);
	bus.bits.cf_bd_endian = value;
	gmac_write_and_check_err_return(bus.u32, base_addr + PPE_CFG_BUS_CTRL_REG);

	return GMAC_OK;
}

/*****************************************************************************
  Function description: set port rx maximum packet length, the packets will be discarded
 *****************************************************************************/
static int gmac_ppe_max_frm_len_set(unsigned long base_addr, unsigned int max)
{
	union rx_max_frame_len len;

	len.u32 = gmac_readl(base_addr + PPE_CFG_MAX_FRAME_LEN_REG);
	len.bits.max_frame_len = max;
	gmac_write_and_check_err_return(len.u32, base_addr + PPE_CFG_MAX_FRAME_LEN_REG);

	return GMAC_OK;
}

static int gmac_max_frame_len_set(unsigned long base_addr, unsigned int max)
{
	union max_frm_size size;

	size.u32 = gmac_readl(base_addr + GE_MAX_FRM_SIZE_REG);
	size.bits.max_frm_size = max;
	gmac_write_and_check_err_return(size.u32, base_addr + GE_MAX_FRM_SIZE_REG);

	return GMAC_OK;
}

static int gmac_short_frame_len_set(unsigned long base_addr, unsigned int len)
{
	union short_framesize frm;

	frm.u32 = gmac_readl(base_addr + GE_SHORT_RUNTS_THR_REG);
	frm.bits.short_runts_thr = len;
	gmac_write_and_check_err_return(frm.u32, base_addr + GE_SHORT_RUNTS_THR_REG);

	return GMAC_OK;
}

static int gmac_tx_add_crc_set(unsigned long base_addr, unsigned int crc_add)
{
	union normal_control ctrl;

	ctrl.u32 = gmac_readl(base_addr + GE_TRANSMIT_CONTROL_REG);
	ctrl.bits.crc_add = crc_add ? 1 : 0;
	gmac_write_and_check_err_return(ctrl.u32, base_addr + GE_TRANSMIT_CONTROL_REG);

	return GMAC_OK;
}

static int gmac_rx_strip_crc_set(unsigned long base_addr, unsigned int en)
{
	union crc_strip crc;

	crc.u32 = gmac_readl(base_addr + GE_CF_CRC_STRIP_REG);
	crc.bits.cf_crc_strip = en ? 1 : 0;   /* Receive CRC strip enable */
	gmac_write_and_check_err_return(crc.u32, base_addr + GE_CF_CRC_STRIP_REG);

	return GMAC_OK;
}

static int gmac_rx_strip_pad_set(unsigned long base_addr, unsigned int en)
{
	union recv_control ctrl;
	/* Ultra-short frame transparent transmission or receiving PAD strip enable */
	ctrl.u32 = gmac_readl(base_addr + GE_RECV_CONTROL_REG);
	ctrl.bits.strip_pad_en = en ? 1 : 0;
	gmac_write_and_check_err_return(ctrl.u32, base_addr + GE_RECV_CONTROL_REG);

	return GMAC_OK;
}

static int gmac_rx_short_frame_recv_set(unsigned long base_addr, unsigned int en)
{
	union recv_control ctrl;
	/* Receive PAD strip enable */
	ctrl.u32 = gmac_readl(base_addr + GE_RECV_CONTROL_REG);
	ctrl.bits.runt_pkt_en = en ? 1 : 0;
	gmac_write_and_check_err_return(ctrl.u32, base_addr + GE_RECV_CONTROL_REG);

	return GMAC_OK;
}

static int gmac_tx_pad_add_set(unsigned long base_addr, unsigned int en)
{
	union normal_control ctrl;
	/* Ultra-short frame transparent transmission */
	ctrl.u32 = gmac_readl(base_addr + GE_TRANSMIT_CONTROL_REG);
	ctrl.bits.pad_enable = en ? 1 : 0;
	gmac_write_and_check_err_return(ctrl.u32, base_addr + GE_TRANSMIT_CONTROL_REG);

	return GMAC_OK;
}

static void gmac_interrupt_mask_set(unsigned long base_addr)
{
	union rx_pkt_cfg cfg;
	union ppe_inten en;
	union ppe_rint rint;

	en.u32 = gmac_readl(base_addr + PPE_INTEN_REG);

	en.bits.tx_bd_addr_fifo_int_msk = ENABLE;
	en.bits.ge_fifo_int_msk       = ENABLE;
	en.bits.ddr_rw_int_msk        = ENABLE;
	en.bits.rx_pkt_int_msk        = ENABLE;
	en.bits.rx_low_qos_int_msk    = ENABLE;
	en.bits.rx_no_buf_int_msk     = ENABLE;
	en.bits.rx_drop_int_msk       = ENABLE;
	en.bits.tx_drop_int_msk       = ENABLE;
	en.bits.rx_rel_bmu_int_msk    = ENABLE;
	en.bits.add_poe_int_msk       = ENABLE;

	en.bits.tx_sram_par_int_msk       = ENABLE;
	en.bits.rx_sram_par_int_msk       = ENABLE;

	gmac_writel(en.u32, (base_addr + PPE_INTEN_REG));
	/* When you set the maximum number of packets receiving terminal, you must first clear the interrupt */
	/* Obtain the value of raw interrupt status register */
	rint.u32 = gmac_readl(base_addr + PPE_RINT_REG);
	/* Rx interrupt clear */
	rint.bits.rx_pkt_int_r = 1;
	gmac_writel(rint.u32, (base_addr + PPE_RINT_REG));

	cfg.u32 = gmac_readl(base_addr + PPE_CFG_RX_PKT_INT_REG);
	cfg.bits.cf_intrpt_pkt = 0x01;
	/* Receive time limit, exceeds the set value, the RSCG is considered as RX timeout */
	cfg.bits.cf_intrpt_time = 0x04;

	gmac_writel(cfg.u32, (base_addr + PPE_CFG_RX_PKT_INT_REG));
}

static int gmac_rx_fifo_set(struct net_device *ndev)
{
	struct gmac_private *gmac_priv = netdev_priv(ndev);
	union rx_fifo_size_cfg cfg;
	unsigned long base_addr = gmac_priv->ppe_base_addr;

	cfg.u32 = gmac_readl(base_addr + PPE_CFG_RX_BUFF_FIFO_SIZE_REG);

	cfg.bits.cf_fifo_en    = 1;       /* Each pool cache address. 0, LIFO. 1, FIFO */
	cfg.bits.cf_start_addr = HI1381_RX_BD_RING_ADDR;
	cfg.bits.cf_depth      = HI1381_RX_BD_RING_SIZE;
	gmac_write_and_check_err_return(cfg.u32, (base_addr + PPE_CFG_RX_BUFF_FIFO_SIZE_REG));

	return GMAC_OK;
}

static int gmac_init_chip(struct net_device *dev)
{
	ppe_pkt_store_ctrl_cfg_s ctrl;
	ppe_pkt_parse_mode_cfg_s pkt_mode;
	struct gmac_private *gmac_priv = netdev_priv(dev);
	unsigned long base_addr = dev->base_addr;
	int  ret;
	unsigned long ppe_base_addr = gmac_priv->ppe_base_addr;

	gmac_grp_vmid_set(base_addr);
	gmac_pool_grp_set(ppe_base_addr);

	gmac_mac_address_set(dev, base_addr);

	/* Initialize the packet according to the port number in the buff
	 * cache storage format parameters and obtaining mode (PCU_RX_CTRL_REG)
	 */
	ctrl.cf_rxbuf_1st_skip1      = GMAC_RX_SKIP1;
	ctrl.cf_buf_n1st_skip        = 0;
	ctrl.cf_rxbuf_1st_skip_size2 = GMAC_RX_SKIP2;
	ctrl.cf_rx_align_num         = GMAC_RX_ALIGN; /* 0 */

	if (gmac_pkt_store_format_set(base_addr, &ctrl) != GMAC_OK)
		return GMAC_ERROR;

	/* Set the packet type and parsing mode */
	pkt_mode.cf_skip1_len  = 0;
	pkt_mode.cf_skip2_len  = 0;
	pkt_mode.cf_parse_mode = 1;

	if (gmac_duplex_type_set(base_addr, 1) != GMAC_OK)
		return GMAC_ERROR;

	if (gmac_pkt_input_parse_mode_set(base_addr, &pkt_mode) != GMAC_OK)
		return GMAC_ERROR;

	if (gmac_bus_ctrl_set(base_addr, 1) != GMAC_OK)
		return GMAC_ERROR;

	if (gmac_rx_fifo_set(dev) != GMAC_OK)
		return GMAC_ERROR;

	if (gmac_ppe_max_frm_len_set(base_addr, GMAC_PPE_RX_PKT_MAX_LEN) != GMAC_OK)
		return GMAC_ERROR;

	if (gmac_max_frame_len_set(base_addr, GMAC_MAX_PKT_LEN) != GMAC_OK)
		return GMAC_ERROR;

	if (gmac_short_frame_len_set(base_addr, GMAC_SHORT_PKT_LEN) != GMAC_OK)
		return GMAC_ERROR;

	if (gmac_tx_add_crc_set(base_addr, 1) != GMAC_OK)
		return GMAC_ERROR;

	if (gmac_rx_strip_crc_set(base_addr, 1) != GMAC_OK)
		return GMAC_ERROR;

	if (gmac_rx_strip_pad_set(base_addr, 1) != GMAC_OK)
		return GMAC_ERROR;

	if (gmac_rx_short_frame_recv_set(base_addr, 1) != GMAC_OK)
		return GMAC_ERROR;

	if ((param_board == BOARD_FPGA) ||
	    (param_board == BOARD_USER_DEF && param_channel == CHANNEL_SPECIAL)) {
		ret = gmac_port_mode_set(base_addr, MAC_100M_MII);
	} else {
		ret = gmac_port_mode_set(base_addr, MAC_100M_SGMII);
	}
	if (ret != GMAC_OK)
		return GMAC_ERROR;

	if (gmac_tx_pad_add_set(base_addr, 1) != GMAC_OK)
		return GMAC_ERROR;

	/* Buffer Management Unit */
	if (gmac_close_bmu(dev) != GMAC_OK)
		return GMAC_ERROR;
	/* Packet Order Enforcer */
	if (gmac_close_poe(dev) != GMAC_OK)
		return GMAC_ERROR;

	return GMAC_OK;
}

static void gmac_rx_fill_buffers(struct net_device *dev)
{
	union rx_buffer_size rx_size;   /* Defines the buffer FIFO buffer size configuration register */
	struct gmac_private *gmac_priv = netdev_priv(dev);
	struct sk_buff **rx_skbuff = gmac_priv->rx_skbuff;
	unsigned long long buf_addr;
	unsigned int i;
	unsigned long ppe_base_addr;

	ppe_base_addr = gmac_priv->ppe_base_addr; /* Configure the buffer FIFO register PPE_COMMON */
	rx_size.u32 = gmac_readl(ppe_base_addr + PPE_CFG_RX_BUFF_FIFO_RX_BUF_SIZE_REG);
	rx_size.bits.cf_rx_frt_skip2 = GMAC_RX_SKIP1;
	rx_size.bits.cf_rx_buf_size = (RX_BUFFER_SIZE / CACHE_LINE_SIZE);
	gmac_writel(rx_size.u32, (ppe_base_addr + PPE_CFG_RX_BUFF_FIFO_RX_BUF_SIZE_REG));

	/* You do not need to perform delay */
	for (i = 0; i < RX_RING_SIZE; i++) {
		buf_addr = virt_to_phys(rx_skbuff[i]->data);
		buf_addr /= CACHE_LINE_SIZE;
		gmac_writel((unsigned int)buf_addr, (ppe_base_addr + PPE_CFG_RX_CFF_ADDR_REG));
	}
}

static int gmac_rx_refill_one_buffer(struct net_device *dev, const unsigned int rx_skb_cur)
{
	struct gmac_private *gmac_priv = netdev_priv(dev);
	struct sk_buff *skb = NULL;
	unsigned long long buf_addr;
	char *desc = NULL;
	/* Configure the buffer FIFO register PPE_COMMON */
	unsigned long ppe_base_addr = gmac_priv->ppe_base_addr;

	skb = dev_alloc_skb(RX_BUFFER_SIZE + NET_SKB_PAD);
	if (skb == NULL) {
		pr_err("dev_alloc_skb failed\n");
		return -ENOMEM;
	}

	skb_reserve(skb, NET_SKB_PAD);
	/* Set Z flag */
	desc = skb->data;
	memset(desc, 0x0, RX_BUFFER_SIZE);

	gmac_priv->rx_skbuff[rx_skb_cur] = skb;

	buf_addr = virt_to_phys(skb->data);
	buf_addr /= CACHE_LINE_SIZE;
	/* Write buffer address to the FIFO, this address must be a physical address */
	gmac_writel((unsigned int)buf_addr, (ppe_base_addr + PPE_CFG_RX_CFF_ADDR_REG));

	return GMAC_OK;
}

#if defined(PRINT_BUF) || defined(PRINT_PKT)
static void gmac_watch_skbuff(const struct sk_buff *skb)
{
	pr_err("skb->head = %#x\n",   (unsigned int)(skb->head));
	pr_err("skb->data = %#x\n",   (unsigned int)(skb->data));
	pr_err("skb->tail = %#x\n",   (unsigned int)(skb->tail));
	pr_err("skb->end  = %#x\n",   (unsigned int)(skb->end));
	pr_err("skb->len  = %#x\n\n", (unsigned int)(skb->len));
}
#endif

static netdev_tx_t  gmac_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
	struct gmac_private *gmac_priv = netdev_priv(dev);
	struct tx_buf_ring *tx_ring   = &gmac_priv->tx_ring;
	struct tx_buf *tx_cur = tx_ring->tx_cur;
	struct tx_buf *tx_free = tx_ring->tx_free;
	union cff_data_num num;
	union tx_des_addr des_addr;
	struct tx_descript *tx_desc = tx_cur->tx_desc;
	unsigned int phy_addr;
	unsigned int count;

#ifdef PRINT_PKT
	gmac_print_pkt(skb->data, skb->len, GMAC_TX);
#endif

	while (*(tx_free->tx_state) == GMAC_TX_END || (tx_free == tx_cur->next)) {
		vtrace(V_INFO, "xmit ok, free skb\n");
		/* free skb */
		dev_kfree_skb_any(tx_free->tx_skb);
		tx_free->tx_skb    = NULL;
		*(tx_free->tx_state) = GMAC_TX_IDLE;

		tx_free = (struct tx_buf *)(tx_free->next);
	}
	/* pTxFree pointer in updated Tx Ring */
	tx_ring->tx_free = tx_free;
	if (skb->len == 0) {
		dev_kfree_skb_any(skb);
		pr_err("packet length is zero\n");
		dev->stats.tx_errors++;
		return NETDEV_TX_OK;
	}

	num.u32 = 0;
	num.u32 = gmac_readl(dev->base_addr + PPE_CURR_CFF_DATA_NUM_REG);
	if (num.bits.tx_cfg_num >= 0x30) {
		dev_kfree_skb_any(skb);
		dev->stats.tx_dropped++;
		dev->stats.tx_errors++;
		return NETDEV_TX_OK;
	}
	/* The maximum packet length is 1518 */
	if (skb->len > GMAC_MAX_PKT_LEN) {
		pr_err("packet length is %d\n", skb->len);
		dev_kfree_skb_any(skb);
		dev->stats.tx_errors++;
		return NETDEV_TX_OK;
	}

	if (*(tx_cur->tx_state) != GMAC_TX_IDLE) {
		pr_err("the ring is full\n");
		dev_kfree_skb_any(skb);
		dev->stats.tx_dropped++;
		dev->stats.tx_errors++;
		return NETDEV_TX_OK;
	}

	memset((void *)tx_desc, 0, sizeof(struct tx_descript));

	/* word0 */
	tx_desc->cl = 1;
	tx_desc->lc = 1;
	tx_desc->pool_num = MAX_POOL_NUM;
	/* word1 */
	tx_desc->data_lenth = skb->len;      /* Length of the data to be sent. */
	if (param_smmu == NO_SMMU) {
		tx_desc->ri = 1;
	} else {
		tx_desc->ri = 0;  /* not invalidate cache */
		tx_desc->ra = 1;  /* read data into cache */
	}

	/* word2 */
	tx_desc->ref_itself_addr_31_0 = (unsigned int)virt_to_phys(skb->data);
	tx_desc->data_offset = (tx_desc->ref_itself_addr_31_0) % CACHE_LINE_SIZE;
	if ((tx_desc->data_offset) != 0) {
		tx_desc->ref_itself_addr_31_0 = ALIGN((tx_desc->ref_itself_addr_31_0), CACHE_LINE_SIZE);
		tx_desc->ref_itself_addr_31_0 -= CACHE_LINE_SIZE;
	}
	/* word3 */
	*(tx_cur->tx_state) = GMAC_TX_START; /* Set the packet sending is complete clear area. */
	/* word4 */
	tx_desc->wb_addr_31_0 = (unsigned int)virt_to_phys(tx_cur->tx_state);
	tx_desc->wb_addr_39_32 = 0;
	tx_cur->tx_skb = skb;
	tx_cur = (struct tx_buf *)(tx_cur->next);
	/* pTxCur pointer in updated Tx Ring */
	tx_ring->tx_cur = tx_cur;

	phy_addr = (unsigned int)virt_to_phys(tx_desc);
	spin_lock(&gmac_priv->spinlock);
	des_addr.u32 = gmac_readl(dev->base_addr + PPE_CFG_TX_PKT_BD_ADDR_REG);
	des_addr.bits.tx_bd_rel = 0x1;
	des_addr.bits.tx_bd_addr = phy_addr >> SHIFT_6_BITS;
	netdev_get_tx_queue(dev, 0)->trans_start = jiffies;
	/* This command is used to register to the packet descriptors, PPE automatically sends packets */
	gmac_writel(des_addr.u32, (dev->base_addr + PPE_CFG_TX_PKT_BD_ADDR_REG));
	spin_unlock(&gmac_priv->spinlock);

	udelay(DELAY_10);
	count = 0;
	while (*(tx_free->tx_state) != GMAC_TX_END) {
		udelay(DELAY_10);
		count++;
		if (count >= GMAC_TX_MAX_PKT) {
			pr_err("[bugfix]: the pkb tx error\n");
			break;
		}
	}

	while (*(tx_free->tx_state) == GMAC_TX_END) {
		vtrace(V_INFO, "[bugfix]: xmit ok, free skb\n");
		dev_kfree_skb_any(tx_free->tx_skb);
		tx_free->tx_skb    = NULL;
		*(tx_free->tx_state) = GMAC_TX_IDLE;

		tx_free = (struct tx_buf *)(tx_free->next);
	}

	tx_ring->tx_free = tx_free;
	dev->stats.tx_bytes += tx_desc->data_lenth;
	dev->stats.tx_packets++;

	return NETDEV_TX_OK;
}

static void gmac_timeout(struct net_device *dev, unsigned int txqueue)
{
	struct gmac_private *gmac_priv  = netdev_priv(dev);

	gmac_priv->statistics.tx_errors++;
	netif_wake_queue(dev);
}

static int gmac_recv_sub0(struct sk_buff **rx_skbuff, unsigned int *rx_skb_cur, struct net_device *dev)
{
	int ret;

	ret = gmac_rx_refill_one_buffer(dev, *rx_skb_cur);
	if (ret != GMAC_OK) {
		rx_skbuff[*rx_skb_cur] = NULL;
		pr_err("gmac_rx_refill_one_buffer fail\n");
	}
	(*rx_skb_cur)++;
	if (*rx_skb_cur == RX_RING_SIZE)
		*rx_skb_cur = 0;

	return 0;
}

int gmac_recv_count;
static int gmac_recv_sub1(struct sk_buff **rx_skbuff,
		struct sk_buff *skb, struct net_device *dev,
		const int *tmp, unsigned int *rx_skb_cur)
{
	int ret;

	if (*tmp == 0)
		gmac_recv_count++;

	if (gmac_recv_count > GMAC_RX_MIN_PKT_LEN) {
		pr_err("pkt len is zero\n");
		ret = gmac_rx_refill_one_buffer(dev, *rx_skb_cur);
		if (ret != GMAC_OK) {
			rx_skbuff[*rx_skb_cur] = NULL;
			pr_err("gmac_rx_refill_one_buffer fail\n");
		}

		dev_kfree_skb_any(skb);
		dev->stats.rx_errors++;
		dev->stats.rx_dropped++;

		(*rx_skb_cur)++;
		if (*rx_skb_cur == RX_RING_SIZE)
			*rx_skb_cur = 0;
	}
	return 0;
}
static int gmac_recv_sub2(struct sk_buff *skb, struct net_device *dev, unsigned int *rx_skb_cur)
{
	dev_kfree_skb_any(skb);

	dev->stats.rx_errors++;
	dev->stats.rx_dropped++;

	(*rx_skb_cur)++;
	if (*rx_skb_cur == RX_RING_SIZE)
		*rx_skb_cur = 0;

	return 0;
}
static void gmac_recv(unsigned long data)
{
	struct net_device *dev = (struct net_device *)(uintptr_t)data;
	struct gmac_private *gmac_priv = netdev_priv(dev);
	struct sk_buff **rx_skbuff  = gmac_priv->rx_skbuff;
	struct sk_buff *skb         = NULL;
	unsigned int			rx_skb_cur  = gmac_priv->rx_skb_cur;
	unsigned int			length;
	unsigned int			l2_err;
	int				ret;
	struct receive_descripte_ppe *recv_desc = NULL;    /* MAC packet descriptors */
	unsigned long			base_addr = dev->base_addr;
	union ppe_inten			en;
	int tmp = 0;
	int recv_pkts = 0;

	while (1) {
		recv_pkts++;
		if (recv_pkts > RECV_MAXPKTS_ONETIME) {
			break;
		}

		if (rx_skbuff[rx_skb_cur] == NULL) {
			(void)gmac_recv_sub0(rx_skbuff, &rx_skb_cur, dev);
			continue;
		}

		skb = rx_skbuff[rx_skb_cur];
		/* cache invalildate */
		/* Obtain the packet descriptor address */
		recv_desc = (struct receive_descripte_ppe *)skb->data;
		/* Obtain the packet length word3.Len */
		length = recv_desc->chain_length;
		if (length == 0) {
			(void)gmac_recv_sub1(rx_skbuff, skb, dev, &tmp, &rx_skb_cur);
			break;
		}
		tmp++;
		gmac_recv_count = 0;

		ret = gmac_rx_refill_one_buffer(dev, rx_skb_cur);
		if (ret != GMAC_OK) {
			rx_skbuff[rx_skb_cur] = NULL;
			pr_err("gmac_rx_refill_one_buffer fail\n");
		}

		if (length >= PACKET_DATA_SIZE) {
			pr_err("pkt too long: %d\n", length);
			(void)gmac_recv_sub2(skb, dev, &rx_skb_cur);
			continue;
		}
		/* check word5.L2_error field */
		l2_err = recv_desc->l2_err & GMAC_DESC_L2_ERR_MASK;
		if (l2_err == GMAC_DESC_L2_ERR_ERROR) {
			pr_err("pkt l2 error\n");

			(void)gmac_recv_sub2(skb, dev, &rx_skb_cur);
			continue;
		}

#ifdef PRINT_PKT
		gmac_print_pkt((char *)recv_desc, GMAC_DESC_LEN, GMAC_RX_DESCRIPTION);
#endif

		skb_reserve(skb, CACHE_LINE_SIZE + NET_IP_ALIGN);

#ifdef PRINT_PKT
		gmac_print_pkt(skb->data, length, GMAC_RX);
#endif

		skb_put(skb, length);           /* Make room */
		skb->protocol = eth_type_trans(skb, dev);

#ifdef PRINT_PKT
		gmac_watch_skbuff(skb);
#endif

		memset(recv_desc, 0x0, GMAC_DESC_LEN);

		dev->stats.rx_bytes += length;
		dev->stats.rx_packets++;

		(void)netif_receive_skb(skb);

		++rx_skb_cur;
		if (rx_skb_cur == RX_RING_SIZE)
			rx_skb_cur = 0;
	}

	gmac_priv->rx_skb_cur = rx_skb_cur;
	/* Enable the Rx interrupt */
	en.u32 = gmac_readl((base_addr + PPE_INTEN_REG));
	en.bits.rx_pkt_int_msk = 1;
	en.bits.rx_no_buf_int_msk = 1;
	gmac_writel(en.u32, (base_addr + PPE_INTEN_REG));
}

static irqreturn_t gmac_interrupt(int irq, void *dev_id)
{
	struct net_device *dev = dev_id;
	struct gmac_private *gmac_priv = netdev_priv(dev);
	unsigned long		base_addr = dev->base_addr;
	union ppe_rint		rint;
	union ppe_intsts	status;
	union ppe_inten		en;
	irqreturn_t		ret = IRQ_HANDLED;

	/* Obtain the interrupt mask register */
	en.u32 = gmac_readl(base_addr + PPE_INTEN_REG);
	/* Obtain the value of raw interrupt status register */
	rint.u32 = gmac_readl(base_addr + PPE_RINT_REG);
	/* Obtain the interrupt status register */
	status.u32 = gmac_readl(base_addr + PPE_INTSTS_REG);
	rint.u32 = 0x7FFFF;
	gmac_writel(rint.u32, (base_addr + PPE_RINT_REG));
	/* bit 10 receive interrupt */
	if ((status.bits.rx_pkt_int_sts) == 1 || status.bits.rx_no_buf_int_sts == 1) {
		/* Rx interrupt is masked */
		en.bits.rx_pkt_int_msk = 0;
		en.bits.rx_no_buf_int_msk = 0;
		gmac_writel(en.u32, (base_addr + PPE_INTEN_REG));
		ret = IRQ_HANDLED;
		tasklet_schedule(&gmac_priv->rx_tasklet);
	}
	return ret;
}

static int gmac_set_mac_address(struct net_device *dev, void *p)
{
	struct sockaddr *addr = p;
	unsigned int mac_addr_l;
	unsigned int mac_addr_h;
	unsigned char len;

	if (!is_valid_ether_addr(addr->sa_data)) {
		pr_err("Invalid ether addr\n");
		return -EADDRNOTAVAIL;
	}
	/* writes the MAC address  net_device structure */
	if (sizeof(addr->sa_data) >= dev->addr_len)
		len = dev->addr_len;
	else
		len = sizeof(addr->sa_data);

	memcpy(dev->dev_addr, addr->sa_data, len);
	/* the MAC address to the chip */
	mac_addr_h  = (dev->dev_addr[OFFSET_0] << SHIFT_8_BITS) | (dev->dev_addr[OFFSET_1]);
	mac_addr_l = (dev->dev_addr[OFFSET_2] << SHIFT_24_BITS)
		| (dev->dev_addr[OFFSET_3] << SHIFT_16_BITS)
		| (dev->dev_addr[OFFSET_4] << SHIFT_8_BITS)
		| (dev->dev_addr[OFFSET_5]);
	pr_err("MAC LOW: %#x\n", gmac_readl(dev->base_addr + GE_STATION_ADDR_LOW_2_REG));

	gmac_writel(mac_addr_l, dev->base_addr + GE_STATION_ADDR_LOW_2_REG);
	gmac_writel(mac_addr_h, dev->base_addr + GE_STATION_ADDR_HIGH_2_REG);
	return GMAC_OK;
}

static void gmac_free_buffers(struct net_device *dev)
{
	struct gmac_private *gmac_priv = netdev_priv(dev);
	struct sk_buff **rx_skbuff = gmac_priv->rx_skbuff;
	struct sk_buff *skb       = NULL;
	unsigned int		i;

	for (i = 0; i < RX_RING_SIZE; i++) {
		if (rx_skbuff[i] != NULL) {
			skb = rx_skbuff[i];
			dev_kfree_skb(skb);
			rx_skbuff[i] = NULL;
		}
	}
}

static int gmac_rx_ring_init(struct net_device *dev)
{
	struct gmac_private *gmac_priv = netdev_priv(dev);
	struct sk_buff **rx_skbuff = gmac_priv->rx_skbuff;
	struct sk_buff *skb = NULL;
	unsigned int		i;
	/* Initialize the receiving Buffer Ring */
	for (i = 0; i < RX_RING_SIZE; i++) {
		skb = dev_alloc_skb(RX_BUFFER_SIZE + NET_SKB_PAD);
		if (skb == NULL) {
			pr_err("dev_alloc_skb failed\n");
			gmac_free_buffers(dev);
			return -ENOMEM;
		}
		skb_reserve(skb, NET_SKB_PAD);
		/* Clearing skb data area, starting from data */
		memset(skb->data, 0x0, RX_BUFFER_SIZE);
		rx_skbuff[i] = skb;
	}
	/* Initialize the receiving skb index */
	gmac_priv->rx_skb_cur  = 0;
	gmac_priv->rx_skb_mask = RX_RING_SIZE - 1; /* For receiving useless */

	/* Viewing the Properties of a skbuff all */
#ifdef PRINT_BUF
	gmac_watch_skbuff(skb);
#endif
	return GMAC_OK;
}

static int gmac_tx_ring_init(struct net_device *dev)
{
	struct gmac_private *gmac_priv  = netdev_priv(dev);
	struct tx_buf_ring *tx_ring    = &gmac_priv->tx_ring;
	struct tx_buf *buf_ring = tx_ring->buf_ring;
	unsigned int		i;

	struct tx_descript *desc = NULL;

	void *clean_addr = NULL;

	clean_addr = kzalloc(((TX_RING_SIZE + 1) * CACHE_LINE_SIZE), GFP_KERNEL);
	if (clean_addr == NULL) {
		pr_err("alloc pTxCleanAddr: Unable to allocate Tx pTxCleanAddr.\n");
		return GMAC_ERROR;
	}

	gmac_priv->ppe_tx_status = clean_addr;
	if ((((unsigned int)(uintptr_t)clean_addr) % CACHE_LINE_SIZE) != 0)
		clean_addr = PTR_ALIGN(clean_addr, CACHE_LINE_SIZE);
	/* Initializing TxBD structure and consists of the TxBD Ring */
	for (i = 0; i < TX_RING_SIZE; i++) {
		buf_ring[i].tx_skb     = NULL;
		buf_ring[i].tx_state = (unsigned int *)(clean_addr + CACHE_LINE_SIZE * i);

		*(buf_ring[i].tx_state) = GMAC_TX_IDLE;
		buf_ring[i].next       = (void *)&(buf_ring[(i + 1) % TX_RING_SIZE]);
	}

	/* Initializing sending skb index */
	tx_ring->tx_cur  = &(buf_ring[0]);
	tx_ring->tx_free = &(buf_ring[0]);

	desc = kzalloc(((TX_RING_SIZE + 1) * CACHE_LINE_SIZE), GFP_KERNEL);
	if (desc == NULL) {
		pr_err("alloc struct tx_descript: Unable to allocate Tx description.\n");
		kfree(gmac_priv->ppe_tx_status);
		return GMAC_ERROR;
	}

	gmac_priv->ppe_tx_desc = desc;
	if ((((unsigned int)(uintptr_t)desc) % CACHE_LINE_SIZE) != 0)
		desc = PTR_ALIGN(desc, CACHE_LINE_SIZE);

	for (i = 0; i < TX_RING_SIZE; i++)
		buf_ring[i].tx_desc = (struct tx_descript *)((unsigned int)(uintptr_t)desc + CACHE_LINE_SIZE * i);

	return GMAC_OK;
}

static int gmac_open(struct net_device *dev)
{
	struct gmac_private *gmac_priv = netdev_priv(dev);
	int ret;
	unsigned long base_addr = dev->base_addr;
	struct phy_device *phydev = gmac_priv->phy;

	netif_start_queue(dev);
	/* Enable the TX channel */
	ret = gmac_set_channel(base_addr, 1, 1);
	if (ret != GMAC_OK) {
		pr_err("gmac_set_channel fail\n");
		return GMAC_ERROR;
	}
	/* Enable the RX channel */
	ret = gmac_set_channel(base_addr, 0, 1);
	if (ret != GMAC_OK) {
		pr_err("gmac_set_channel fail\n");
		return GMAC_ERROR;
	}
	/* Associated rx_tasklet processing function */
	gmac_priv->rx_tasklet.next  = NULL;
	gmac_priv->rx_tasklet.state = 0;
	gmac_priv->rx_tasklet.func  = gmac_recv;
	gmac_priv->rx_tasklet.data  = (unsigned long)(uintptr_t)dev;
	/* Enable the interrupt */
	gmac_interrupt_mask_set(base_addr);

	if (phydev && !IS_ERR(phydev) && param_phy_start)
		phy_start(phydev);

	return GMAC_OK;
}

static int gmac_stop(struct net_device *dev)
{
	unsigned long base_addr = dev->base_addr;
	int  ret;
	union ppe_inten en;

	netif_stop_queue(dev);
	/* Disable the transmit channel */
	ret = gmac_set_channel(base_addr, 1, 0);
	if (ret != GMAC_OK) {
		pr_err("gmac_set_channel fail\n");
		return GMAC_ERROR;
	}
	/* The RX channel */
	ret = gmac_set_channel(base_addr, 0, 0);
	if (ret != GMAC_OK) {
		pr_err("gmac_set_channel fail\n");
		return GMAC_ERROR;
	}
	/* 0: Disable the interrupt */
	en.u32 = gmac_readl(base_addr + PPE_INTEN_REG);
	en.bits.rx_pkt_int_msk = DISABLE;
	gmac_write_and_check_err_return(en.u32, (base_addr + PPE_INTEN_REG));
	return GMAC_OK;
}

static int gmac_close(struct net_device *dev)
{
	struct gmac_private *gmac_priv = netdev_priv(dev);
	struct phy_device   *phydev = gmac_priv->phy;
	int  ret;

	ret = gmac_stop(dev);
	tasklet_kill(&gmac_priv->rx_tasklet);
	if ((phydev != NULL) && !IS_ERR(phydev) && param_phy_start)
		phy_stop(phydev);
	return ret;
}

int gmac_change_mtu(struct net_device *dev, int new_mtu)
{
	if (new_mtu < MIN_MTU_LEN || new_mtu > ETH_DATA_LEN)
		return -EINVAL;
	dev->mtu = new_mtu;
	return 0;
}

static const struct net_device_ops gmac_netdev_ops = {
	.ndo_open               = gmac_open,
	.ndo_stop               = gmac_close,
	.ndo_start_xmit         = gmac_start_xmit,
	.ndo_change_mtu         = gmac_change_mtu,
	.ndo_validate_addr      = eth_validate_addr,
	.ndo_tx_timeout         = gmac_timeout,
	.ndo_set_mac_address    = gmac_set_mac_address,
};

static struct device_node *phy_node;

static void gmac_adjust_link(struct net_device *dev)
{
	int speed;
	int duplex_type;
	struct gmac_private *gmac_priv = netdev_priv(dev);
	unsigned long base_addr = dev->base_addr;
	int port_mode;
	struct phy_device *phydev = gmac_priv->phy;

	speed  = phydev->speed;
	duplex_type = phydev->duplex;

	if (phydev->link != gmac_priv->link_old) {
		pr_err("now the net states is %d", phydev->link);
		gmac_priv->link_old = phydev->link;
	}
	if (duplex_type != gmac_priv->duplex_old) {
		spin_lock(&gmac_priv->spinlock);
		if (gmac_duplex_type_set(base_addr, duplex_type) != GMAC_OK)
			pr_err("fail to set gmac-duplex-type\n");
		spin_unlock(&gmac_priv->spinlock);
		gmac_priv->duplex_old = duplex_type;
	}
	if (speed != gmac_priv->speed_old) {
		switch (speed) {
		case SPEED_100:
			port_mode = MAC_100M_MII;
			break;
		case SPEED_10:
			port_mode = MAC_10M_MII;
			break;
		default:
			return;
		}
		spin_lock(&gmac_priv->spinlock);
		if (gmac_port_mode_set(base_addr, port_mode) != GMAC_OK)
			pr_err("gmac_port_mode_set fail\n");

		spin_unlock(&gmac_priv->spinlock);
		gmac_priv->speed_old = speed;
	}
}

static unsigned int gmac_trans_speed_to_mode(unsigned int speed)
{
	unsigned int mode;

	switch (speed) {
	case SGMII_1000M:
		mode = MAC_1000M_SGMII;
		break;
	case SGMII_100M:
		mode = MAC_100M_SGMII;
		break;
	case SGMII_10M:
		mode = MAC_10M_SGMII;
		break;
	default:
		mode = MAC_10M_SGMII;
		pr_err("NEG speed status error:%d, set 10M as default\n", speed);
		break;
	}

	return mode;
}

static int gmac_adjust(void *param)
{
	struct net_device *dev = (struct net_device *)param;
	struct gmac_private *gmac_priv  = netdev_priv(dev);
	unsigned int link_state = 0;
	unsigned int neg_state = 1;
	union an_neg_state state;
	union port_mode mode;
	unsigned long base_addr = dev->base_addr;

	while (1) {
		if (thread_end == 1) {
			pr_err("the gmac_adjust thread is end\n");
			break;
		}
		state.u32 = gmac_readl(base_addr + GE_AN_NEG_STATE);
		/* SGMII self-negotiation not completed */
		if (!state.bits.an_done) {
			if (neg_state == 1) {
				pr_warn("gmac adjust time out\n");
				neg_state = 0;
			}
			goto out;
		} else {
			if (neg_state == 0) {
				pr_info("gmac adjust success\n");
				neg_state = 1;
			}
		}
		/* phy links at the bottom layer. */
		if (state.bits.np_link_ok) {
			if (link_state == 0) {
				link_state = 1;
				pr_err("now the net phy is connected\n");
				spin_lock(&gmac_priv->spinlock);
				mode.u32 = gmac_readl(base_addr + GE_PORT_MODE_REG);
				mode.bits.port_mode = gmac_trans_speed_to_mode(state.bits.speed);
				gmac_writel(mode.u32, base_addr + GE_PORT_MODE_REG);
				spin_unlock(&gmac_priv->spinlock);
			}
		} else {
			if (link_state == 1) {
				link_state = 0;
				pr_err("now the net phy is disconnected\n");
			}
		}
out:
		(void)msleep_interruptible(SLEEP_500);
	}
	pr_info("the gmac_adjust is done\n");
	return 0;
}

static int gmac_init(struct net_device *ndev)
{
	int ret;
	/* Initializing the GMAC chip */
	ret = gmac_init_chip(ndev);
	if (ret != GMAC_OK) {
		pr_err("gmac_init_chip failed\n");
		return GMAC_ERROR;
	}
	ret = gmac_rx_ring_init(ndev);
	if (ret != GMAC_OK) {
		pr_err("gmac_rx_init_chip failed\n");
		return GMAC_ERROR;
	}
	ret = gmac_tx_ring_init(ndev);
	if (ret != GMAC_OK) {
		pr_err("gmac_tx_init_chip failed\n");
		return GMAC_ERROR;
	}
	gmac_rx_fill_buffers(ndev);

	return GMAC_OK;
}

static int gmac_phy_init(struct net_device *ndev, struct gmac_private *gmac_priv, struct phy_device **phydev)
{
	int ret;
	union curr_buf_cnt cnt;
	unsigned char phyname[MII_BUS_ID_SIZE];

	pr_info("disable PPE reset status\n");
	gmac_writel(0xFFFFFFFF, gmac_priv->sys_ctrl_base_addr + SC_PPE_RESET_DREQ);

	cnt.u32 = gmac_readl((gmac_priv->ppe_base_addr + PPE_CURR_BUF_CNT_REG));
	if (cnt.bits.buf_cnt != 0)
		pr_err("PPE Buff FIFO is not NULL! Cnt = %d\n", cnt.bits.buf_cnt);

	while (cnt.bits.buf_cnt != 0) {
		(void)gmac_readl(gmac_priv->ppe_base_addr + PPE_CFG_RX_CFF_ADDR_REG);
		cnt.u32 = gmac_readl((gmac_priv->ppe_base_addr + PPE_CURR_BUF_CNT_REG));
	}

	spin_lock_init(&gmac_priv->spinlock);
	ret = gmac_init(ndev);
	if (ret != GMAC_OK) {
		pr_err("gmac_init failed\n");
		return GMAC_ERROR;
	}

	snprintf(phyname, sizeof(phyname), "%s-%u:%02x", GMAC_MDIOBUS_NAME, param_mdio_num, param_phy_num);
	gmac_priv->phy_name = phyname;

	if ((param_board == BOARD_FPGA) ||
	    (param_board == BOARD_USER_DEF && param_channel == CHANNEL_SPECIAL)) {
		if (phy_node)
			*phydev = of_phy_connect(ndev, phy_node, &gmac_adjust_link, 0, PHY_INTERFACE_MODE_MII);
		if (IS_ERR(*phydev)) {
			pr_err("connect to phy_device failed!\n");
			return GMAC_ERROR;
		}
	} else if ((param_board == BOARD_UBBPD) ||
		   (param_board == BOARD_UBBPV2) ||
		   (param_board == BOARD_USER_DEF && param_channel < CHANNEL_SPECIAL)) {
		union normal_control untranctrl;

		untranctrl.u32 = gmac_readl(ndev->base_addr + GE_TRANSMIT_CONTROL_REG);
		untranctrl.bits.an_enable = 1;  /* SGMII self-negotiation enable */
		gmac_writel(untranctrl.u32, ndev->base_addr + GE_TRANSMIT_CONTROL_REG);
		/* Set the working mode of the GE  new threads */
		mytask = kthread_run(gmac_adjust, ndev, "gmac_phy_monitor");
		if (mytask == NULL)
			pr_err("gmac kthread_run error.\n");
	} else {
		pr_err("Board type ERROR! %d\n", param_board);
		return GMAC_ERROR;
	}
	gmac_priv->phy = *phydev;
	return 0;
}

static int gmac_irq_init(struct platform_device *dev, struct net_device *ndev)
{
	int irq;
	int ret;

	irq = platform_get_irq(dev, 0);
	if (irq < 0) {
		pr_err("platform_get_irq failed\n");
		return GMAC_ERROR;
	}
	pr_err("interrupt num %d\n", irq);

	ret = request_irq(irq, gmac_interrupt, 0, dev->name, ndev);
	if (ret) {
		pr_err("request_irq failed\n");
		return GMAC_ERROR;
	}

	return 0;
}

static void gmac_unmap(struct net_device *ndev, struct gmac_private *gmac_priv)
{
	if (gmac_priv->sys_ctrl_base_addr != 0)
		gmac_iounmap(gmac_priv->sys_ctrl_base_addr);
	if (gmac_priv->ppe_base_addr != 0)
		gmac_iounmap(gmac_priv->ppe_base_addr);
	if (ndev->base_addr != 0)
		gmac_iounmap(ndev->base_addr);
}

static int gmac_map(struct platform_device *dev, struct net_device *ndev, struct gmac_private *gmac_priv)
{
	struct resource         *res = NULL;

	res = platform_get_resource(dev, IORESOURCE_MEM, 0);
	if (res == NULL) {
		pr_err("platform_get_resource failed\n");
		return -ENXIO;
	}

	res = request_mem_region(res->start, resource_size(res), dev->name);
	if (res == NULL) {
		pr_err("request_mem_region failed\n");
		return -EBUSY;
	}

	ndev->base_addr = gmac_ioremap(res->start, resource_size(res));
	if (ndev->base_addr == 0) {
		pr_err("ioremap failed\n");
		goto _error_failed_register;
	}

	gmac_priv->ppe_base_addr = gmac_ioremap(GMAC_PPE_COMMON_BASE, GMAC_PPE_COMMON_SIZE);
	if (gmac_priv->ppe_base_addr == 0) {
		pr_err("ioremap failed\n");
		goto _error_failed_register;
	}

	gmac_priv->sys_ctrl_base_addr = gmac_ioremap(SC_BASE_ADDR, 0x750);
	if (gmac_priv->sys_ctrl_base_addr == 0) {
		pr_err("ioremap failed\n");
		goto _error_failed_register;
	}

	return 0;

_error_failed_register:
	(void)gmac_unmap(ndev, gmac_priv);
	release_mem_region(res->start, resource_size(res));
	return -1;
}

static struct ethtool_ops gmac_ethtool_ops = {
	.nway_reset		= phy_ethtool_nway_reset,
	.get_link		= ethtool_op_get_link,
};

static int gmac_probe(struct platform_device *dev)
{
	struct gmac_private *gmac_priv = NULL;
	struct net_device *ndev = NULL;
	struct phy_device *phydev = NULL;
	int irq = -1;
	int ret;

	phy_node = of_parse_phandle(dev->dev.of_node, "phy-handle", 0);
	/* Init network device */
	ndev = alloc_netdev(sizeof(struct gmac_private), "HiFE%d", NET_NAME_UNKNOWN, ether_setup);
	if (ndev == NULL) {
		pr_err("alloc_netdev failed\n");
		return -ENOMEM;
	}

	SET_NETDEV_DEV(ndev, &dev->dev);
	gmac_priv = netdev_priv(ndev);
	memset(gmac_priv, 0, sizeof(*gmac_priv));

	if (gmac_map(dev, ndev, gmac_priv) != 0)
		goto _error_failed_map;
	/* The GMAC-specific entries in the device structure. */
	ndev->netdev_ops = &gmac_netdev_ops;
	ndev->ethtool_ops = &gmac_ethtool_ops; /* &rtl8139_ethtool_ops; */
	ndev->watchdog_timeo = TX_TIMEOUT;

	if (gmac_phy_init(ndev, gmac_priv, &phydev) != 0)
		goto _error_failed_register;

	if (gmac_irq_init(dev, ndev) != 0)
		goto _error_failed_register;

	ret = register_netdev(ndev);
	if (ret != GMAC_OK) {
		pr_err("register_netdev failed\n");
		free_irq(irq, ndev);
		goto _error_failed_phy_connect;
	}
	platform_set_drvdata(dev, ndev);

	return ret;

_error_failed_phy_connect:
	if ((phydev != NULL) && !IS_ERR(phydev))
		phy_disconnect(phydev);
_error_failed_register:
	gmac_unmap(ndev, gmac_priv);
_error_failed_map:
	free_netdev(ndev);

	return GMAC_ERROR;
}

static int  gmac_drv_remove(struct platform_device *dev)
{
	struct net_device *ndev = platform_get_drvdata(dev);
	struct gmac_private *gmac_priv = netdev_priv(ndev);
	struct resource *res = NULL;
	int ret = 0;
	int irq;
	void *tx_status  = NULL;
	void *tx_desc = NULL;
	struct phy_device *phy_dev = NULL;

	if (mytask != NULL) {
		thread_end = 1;
		kthread_stop(mytask);
		pr_err("stop mytask end\n");
		mytask = NULL;
	}

	if (ndev != NULL) {
		platform_set_drvdata(dev, NULL);
		unregister_netdev(ndev);
		irq =  platform_get_irq(dev, 0);
		if (irq > 0)
			free_irq(irq, ndev);

		phy_dev = gmac_priv->phy;
		if ((phy_dev != NULL) && !IS_ERR(phy_dev))
			phy_disconnect(phy_dev);

		gmac_unmap(ndev, gmac_priv);
		res = platform_get_resource(dev, IORESOURCE_MEM, 0);
		if (res != NULL)
			release_mem_region(res->start, resource_size(res));

		tx_desc = gmac_priv->ppe_tx_desc;
		tx_status  = gmac_priv->ppe_tx_status;
		/* Release memory for sending packet descriptors */
		if (tx_desc != NULL) {
			kfree(tx_desc);
			tx_desc = NULL;
			kfree(tx_status);
			tx_status = NULL;
		}
		/* Rx ring release application skb */
		gmac_free_buffers(ndev);
		free_netdev(ndev);
	}

	return ret;
}

static int gmac_suspend(struct platform_device *dev, pm_message_t state)
{
	struct net_device *ndev = platform_get_drvdata(dev);
	int  ret = GMAC_OK;

	if (ndev != NULL) {
		if (netif_running(ndev)) {
			netif_device_detach(ndev);
			ret = gmac_stop(ndev);
		}
	}

	return ret;
}

static int gmac_resume(struct platform_device *dev)
{
	struct net_device *ndev = platform_get_drvdata(dev);
	int ret = GMAC_OK;

	if (ndev != NULL) {
		if (netif_running(ndev)) {
			netif_device_attach(ndev);
			ret = gmac_open(ndev);
		}
	}

	return ret;
}

static void gmac_shutdown(struct platform_device *dev)
{
	struct net_device *ndev = platform_get_drvdata(dev);

	if (ndev != NULL) {
		if (netif_running(ndev)) {
			netif_device_detach(ndev);
			if (gmac_stop(ndev) != GMAC_OK)
				pr_err("gmac_stop fail\n");
		}
	}
}

static void gmac_platform_device_release(struct device *dev)
{
	pr_info("gmac device release\n");
}

static struct resource gmac_resources[] = {
	[0] = {
		.start = GMAC_DEV_IOBASE,
		.end   = GMAC_DEV_IOBASE + GMAC_DEV_IOSIZE - 1,
		.flags = IORESOURCE_MEM,
	},
	[1] = {
		.start = GMAC_DEV_IRQNUM,
		.end   = GMAC_DEV_IRQNUM,
		.flags = IORESOURCE_IRQ,
	}
};

static struct platform_device gmac_platform_device = {
	.name = GMAC_DEV_NAME,
	.id   = 0,
	.dev = {
		.platform_data = NULL,
		.dma_mask = (u64 *)~0,
		.coherent_dma_mask = (u64)~0,
		.release = gmac_platform_device_release,
	},
	.num_resources = ARRAY_SIZE(gmac_resources),
	.resource = gmac_resources,
};

static const struct of_device_id hi1381gmac_of_match[] = {
	{ .compatible = "hisilicon,hip04-mac" },
	{ }
};

static struct platform_driver gmac_driver = {
	.driver = {
		.name    = GMAC_DEV_NAME,
		.of_match_table   = hi1381gmac_of_match,
		.owner   = THIS_MODULE,
	},
	.probe   = gmac_probe,
	.remove  = gmac_drv_remove,
	.suspend = gmac_suspend,
	.resume  = gmac_resume,
	.shutdown = gmac_shutdown,
};

static int check_param(void)
{
	if (param_channel > MAX_CHANNEL_NUM) {
		pr_err("param channel is error:%d\n", param_channel);
		return GMAC_ERROR;
	}
	if (param_pool > MAX_POOL_NUM) {
		pr_err("param pool is error:%d\n", param_pool);
		return GMAC_ERROR;
	}
	if (param_group > MAX_GROUP_NUM) {
		pr_err("param group is error:%d\n", param_group);
		return GMAC_ERROR;
	}
	if (param_fifo_start > MAX_FIFO_NUM - 1) {
		pr_err("param fifo_start is error:%d\n", param_fifo_start);
		return GMAC_ERROR;
	}
	if ((param_fifo_size == 0) ||
		(param_fifo_size > MAX_FIFO_NUM) ||
		(param_fifo_start + param_fifo_size > MAX_FIFO_NUM)) {
		pr_err("param fifo_size is error:%d\n", param_fifo_size);
		return GMAC_ERROR;
	}
	if (param_mdio_num > MAX_MDIO_NUM) {
		pr_err("param mdio_num is error:%d\n", param_mdio_num);
		return GMAC_ERROR;
	}
	if (param_phy_num > MAX_PHY_NUM) {
		pr_err("param phy_num is error:%d\n", param_phy_num);
		return GMAC_ERROR;
	}
	return GMAC_OK;
}

void __iomem *hi_cpu_gpio_base;
#define HI_CPU_GPIO_INT_EN_REG	0x30
#define HI_CPU_GPIO_DIR_REG	0x4
static u32 hi_cpu_gpio_reg_read(u32 port, u32 reg)
{
	if (hi_cpu_gpio_base != 0)
		return readl(hi_cpu_gpio_base + port * 0x1000 + reg);
	else
		return 0;
}

static void hi_cpu_gpio_reg_write(u32 port, u32 reg, u32 val)
{
	if (hi_cpu_gpio_base != 0)
		writel(val, hi_cpu_gpio_base + port * 0x1000 + reg);
}

static void hisi_port_init(u32 port_no, u32 pin_no, u32 dir)
{
	u32 reg_val = 0;
	/* set the port as gpio port */
	reg_val = hi_cpu_gpio_reg_read(port_no, HI_CPU_GPIO_INT_EN_REG);
	reg_val &= ~pin_no;
	hi_cpu_gpio_reg_write(port_no, HI_CPU_GPIO_INT_EN_REG, reg_val);
	/* set the port as output or input */
	reg_val = hi_cpu_gpio_reg_read(port_no, HI_CPU_GPIO_DIR_REG);
	if (dir == OUTPUT_PIN)
		reg_val |= pin_no;
	else
		reg_val &= ~pin_no;
	hi_cpu_gpio_reg_write(port_no, HI_CPU_GPIO_DIR_REG, reg_val);
}

static u32 hisi_get_port_level(u32 port_no, u32 pin_no)
{
	u32 reg_val = 0;
	/* set the port as input */
	reg_val = hi_cpu_gpio_reg_read(port_no, HI_CPU_GPIO_DIR_REG);
	reg_val &= ~pin_no;
	hi_cpu_gpio_reg_write(port_no, HI_CPU_GPIO_DIR_REG, reg_val);
	reg_val = hi_cpu_gpio_reg_read(port_no, HI_CPU_GPIO_INPUT_REG);
	if (reg_val & pin_no) {
		return HIGH_LEVEL;
	} else {
		return LOW_LEVEL;
	}
}

static int gmac_need_not_init(void)
{
	unsigned int reg_value;
	unsigned int old_value;
	void __iomem *reg_point = NULL;

	hi_cpu_gpio_base = ioremap(IO_BASE_ADDR, 0x4000);
	if (hi_cpu_gpio_base == 0) {
		pr_err("ioremap hi_cpu_gpio_base err in gmac_need_not_init!\n");
		return 1;
	}
	hisi_port_init(GPIO_PORT_3, GPIO_PIN_112, INPUT_PIN);
	reg_point = ioremap(IOCONFIG_BASE_ADDR, 0x1000);
	if (reg_point == 0) {
		iounmap((void *)hi_cpu_gpio_base);
		pr_err("ioremap reg_point err in gmac_need_not_init!\n");
		return 1; /* need not init gmac if ioremap error */
	}

	old_value = readl(reg_point + IOMG058);
	writel(0x1, (reg_point + IOMG058));
	reg_value = hisi_get_port_level(GPIO_PORT_3, GPIO_PIN_112);
	writel(old_value, (reg_point + IOMG058));
	iounmap((void *)reg_point);
	iounmap((void *)hi_cpu_gpio_base);

	if (reg_value == HIGH_LEVEL)
		return 1; /* High level, need not init gmac */
	else
		return 0; /* Low level, need init gmac */
}

static int __init gmac_module_init(void)
{
	int ret;
	struct resource *rsc = gmac_platform_device.resource;

	ret = check_param();
	if (ret) {
		pr_err("gmac param is error, please try again with suitable param.\n");
		return GMAC_ERROR;
	}

	if (param_board == BOARD_UBBPD) {
		gmac_not_exist = gmac_need_not_init();
		if (gmac_not_exist) {
			printk("Debug gmac need not init, because no optical module.\n");
			return GMAC_ERROR;
		}
	}
	pr_err("----------> debug <----------\n");
	pr_err("- print_err addr %#x -\n", (unsigned int)virt_to_phys(&print_err));
	pr_err("----------> debug <----------\n");
	/* ubbp D board */
	if (param_board == BOARD_UBBPD) {
		rsc[0].start = hi1381_ubbp_d.gmac_iobase;
		rsc[0].end = hi1381_ubbp_d.gmac_iobase + GMAC_DEV_IOSIZE - 1;
		rsc[1].start = rsc[1].end = hi1381_ubbp_d.gmac_irqnum;
	}
	/* ubbp V2 board */
	if (param_board == BOARD_UBBPV2) {
		rsc[0].start = hi1381_ubbp_v2.gmac_iobase;
		rsc[0].end = hi1381_ubbp_v2.gmac_iobase + GMAC_DEV_IOSIZE - 1;
		rsc[1].start = rsc[1].end = hi1381_ubbp_v2.gmac_irqnum;
	}

	if (param_board == BOARD_USER_DEF) {
		resource_size_t channel_num = (resource_size_t)param_channel;

		rsc[0].start = GMAC_BASE_ADDR + channel_num * GMAC_DEV_IOSIZE;
		rsc[0].end =  GMAC_BASE_ADDR + (channel_num + 1) * GMAC_DEV_IOSIZE - 1;
		rsc[1].start = GMAC_BASE_IRQNUM + channel_num;
	}
	ret = platform_driver_register(&gmac_driver);
	if (ret != GMAC_OK) {
		pr_err("Register Net device driver failed\n");
		return GMAC_ERROR;
	}
	return ret;
}

static void __exit gmac_cleanup(void)
{
	platform_driver_unregister(&gmac_driver);
}

module_init(gmac_module_init);
module_exit(gmac_cleanup);

MODULE_DESCRIPTION("Hisilicon GMAC driver");
MODULE_AUTHOR("HUAWEI");
MODULE_LICENSE("GPL");
